/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package cz.dusa.switco;

import java.util.ArrayList;
import java.util.List;

/**
 * Class representing a task.
 * @author vdusa
 */
public class Task {
    private ConvexCostFunction costFunction;
    private Double processingTime = 0.0;
    private EqualityTree equalityTree = null;
    private List<Precedence> predecessors = new ArrayList<Precedence>();
    private List<Precedence> successors = new ArrayList<Precedence>();
    private double treeShift = 0;
    private Long id = null;

    public Task(Long id, ConvexCostFunction costFunction, Double processingTime){
        this.setId(id);
        this.setCostFunction(costFunction);
        this.setProcessingTime(processingTime);
    }

    /**
     * @return the costFunction
     */
    public ConvexCostFunction getCostFunction() {
        return costFunction;
    }

    /**
     * For more information see {@link cz.dusa.switco.ConvexCostFunction}.
     * If your cost function is not complicated, you can use {@link cz.dusa.switco.DefaultConvexCostFunction}
     * @param costFunction the costFunction to set
     */
    public final void setCostFunction(ConvexCostFunction costFunction) {
        this.costFunction = costFunction;
    }

    public double evaluateCostFunction(Double t){
        return getCostFunction().evaluate(t);
    }

    /**
     * @return the processingTime of the Task
     */
    public Double getProcessingTime() {
        return processingTime;
    }

    /**
     * @param processingTime sets the processing time of the task
     */
    public final void setProcessingTime(Double processingTime) {
        this.processingTime = processingTime;
    }

    public void setEqualityTree(EqualityTree equalityTree) {
        this.equalityTree = equalityTree;
    }

    public EqualityTree getEqualityTree(){
        return this.equalityTree;
    }

    /**
     * @return the predecessors
     */
    public List<Precedence> getPredecessors() {
        return predecessors;
    }

    /**
     * @return the successors
     */
    public List<Precedence> getSuccessors() {
        return successors;
    }
    
    /**
     * @return the predecessors according to the given tree
     */
    //@performance of this function can be improved if these precedences will be stored also directly in the task, but I don't have a time to do it now.
    public List<Precedence> getPredecessorsInEqualityTree(EqualityTree tree) {
        List<Precedence> predecessorsInEqualityTree = new ArrayList<Precedence>();
        for(Precedence p: predecessors){
            if(tree.getTreePrecedences().contains(p)){
                predecessorsInEqualityTree.add(p);
            }
        }
        return predecessorsInEqualityTree;
    }

    /**
     * @return the successors
     */
    //@performance of this function can be improved if these precedences will be stored also directly in the task, but I don't have a time to do it now.    
    public List<Precedence> getSuccessorsInEqualityTree(EqualityTree tree) {
        List<Precedence> successorsInEqualityTree = new ArrayList<Precedence>();
        for(Precedence p: successors){
            if(tree.getTreePrecedences().contains(p)){
                successorsInEqualityTree.add(p);
            }
        }
        return successorsInEqualityTree;
    }    
    
    /**
     * Adds the precedence into the list of predecessors
     * @param precedence 
     */
    public void addPredecessor(Precedence precedence){
        assert precedence.getSuccessor().equals(this) : "Precedence doesn't belong to this task.";
        predecessors.add(precedence);
    }
    
    /**
     * Adds the precedence into the list of successors
     * @param precedence 
     */    
    public void addSuccessor(Precedence precedence){
        assert precedence.getPredecessor().equals(this) : "Precedence doesn't belong to this task.";
        successors.add(precedence);
    }

    /**
     * @return start of the task, which is calculated as a start of equality tree
     * which the task belongs to plus shift within this tree. See {@link #setTreeShift(double)}.
     */
    public double getStart() {
        assert getEqualityTree() != null : "Determining start of a task with null equality tree.";
        return getTreeShift() + getEqualityTree().getStart();
    }

    /**
     * @return finish of the task
     */
    public double getFinish(){
        return getStart() + getProcessingTime();
    }

    /**
     * @return start shift within the equality tree
     */
    public double getTreeShift() {
        assert getEqualityTree() != null : "Determining start shift with null equality tree.";
        return treeShift;
    }

    /**
     * @param treeShift the start shift within the equality tree
     */
    public void setTreeShift(double treeShift) {
        assert getEqualityTree() != null : "Setting start shift of an activity without reference to any equality tree.";
        //ConvexCostFunction cf = getCostFunction();
        getCostFunction().setTimeShift(treeShift);
        this.treeShift = treeShift;
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public final void setId(Long id) {
        this.id = id;
    }

    @Override
    public String toString(){
        return getId().toString();
    }
}
